/**
 * 
 */
package archsw0904.controller.authentication;

import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TimedObject;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import archsw0904.controller.shopping.cart.CartBeanLocal;
import archsw0904.controller.shopping.common.CartException;
import archsw0904.model.Authenticated;
import archsw0904.model.Book;
import archsw0904.model.Cart;
import archsw0904.model.OrderedCopies;
import archsw0904.model.ProfileAdmin;
import archsw0904.model.ProfileClient;
import archsw0904.model.ProfileUser;


/**
 * @author ASGroup0904
 *
 */
@Stateless
@WebService
public class AuthenticationManager implements TimedObject, AuthenticationManagerRemote, AuthenticationManagerLocal {
	

	@PersistenceContext
	private EntityManager em ;
	
	@Resource
	private TimerService timerService;

	@EJB
	private CartBeanLocal carrello;

	@WebMethod
	public int logIn(String username, String password) {
		Query query = em.createNamedQuery("ProfileUser.findLoginId").setParameter("loginId", username);
		ProfileUser user;
		
		try {
			user = (ProfileUser) query.getSingleResult();
		} catch (NoResultException e) {
			return -1;
		}	
		
		query = em.createQuery("SELECT OBJECT(obj) FROM Authenticated obj WHERE obj.user = " + user.getId());
		
		try {
			Authenticated authenticated = (Authenticated) query.getSingleResult();
			logOut(authenticated.getId());
		} catch (NoResultException e) {
		}
		
		if ( password.compareTo(user.getPassword()) != 0 ) {
			return -1;
		}
		System.out.println("identita' verificata");
		
		Authenticated auth = new Authenticated();
		auth.setUser(user);
		auth.setLastAccess( new Date() );
		em.persist(auth);
		
		createEspireTimer(auth.getId());
		try {
			ProfileClient client = null;
			client = em.find(ProfileClient.class, auth.getUser().getId());
			if (client != null)
				carrello.createCart(auth.getUser().getId());
		} catch (CartException e) {
			e.printStackTrace();
		} 
		return auth.getId();
	}

	@WebMethod
	public void logOut(int token) {
		Authenticated auth = em.find( Authenticated.class, new Integer(token));
		if (auth!=null){
			ProfileUser pc = (ProfileUser)auth.getUser();
			Cart cart=null;

			Query q = em.createQuery("SELECT OBJECT(obj) FROM Cart obj WHERE obj.client = " + pc.getId().toString() );
			if ( q != null ) {
				if ( !q.getResultList().isEmpty() ) {
					cart = (Cart) q.getSingleResult() ;
					if ( cart == null ) System.out.print("authemticationManagerLogout ERROR 3");
					if ( cart.getClient().getId().equals(token) )System.out.print("authemticationManagerLogout ERROR 4");
				}
			}
			ProfileClient client = null;
			client = em.find(ProfileClient.class, auth.getUser().getId());

			if (client != null){
				//svuoto carrello
				ArrayList<OrderedCopies> oc = new ArrayList<OrderedCopies>() ; 
				ArrayList<Book> b = new ArrayList<Book>() ; 
				
				Map<Book,OrderedCopies> mapList = cart.getCartLines();
				
				for ( Book book : mapList.keySet() ) {
					// ripristino numero di copie available del libro
					
					// correttezza del numero di copie rilasciate
					// magazzino
					if ( book.getCopiesInStockroom().intValue() < (book.getAvailableCopies().intValue() + mapList.get(book).getNumberOfCopies().intValue()) ) 
						System.out.print("errore  authentication manager!!!!!!!!!!");//throw new OrderException ( OrderExceptionType.TooManyCopies ) ;
							
					// aggiornamento copie nel libro		
					book.addAvailableCopies(mapList.get(book).getNumberOfCopies()) ;

					em.persist(book) ;
					
					// rimozione del numero di copie dalla persistenza
					System.out.println("PRE GET MAP") ;
					oc.add(mapList.get(book)) ;
					b.add(book);
					System.out.println("POST GET MAP") ;

				}

				System.out.println("PRE RIMOZIONE ARRAY BOOK") ;
				while ( !b.isEmpty() ) { 
					System.out.println("RIMUOVO " + b.get(0).getId()) ;
					mapList.remove(b.remove(0)) ; 
					}
				
				System.out.println("PRE RIMOZIONE ARRAY COPIES") ;
				while ( !oc.isEmpty() ) { 
					System.out.println("RIMUOVO " + oc.get(0).getId().toString()) ;
					em.remove(oc.remove(0)) ; 
					}
				
				em.remove(cart);
				System.out.print("logout " + auth.getUser().getId());
			}
				 
			else System.out.print("no logout " + auth.getUser().getId());
			em.remove(auth);
		}
		
	}
	
	@WebMethod
	public Integer getUserIdByToken(Integer token) {
		Integer ret = null;
		
		Authenticated auth = em.find(Authenticated.class, token);
		
		if (auth == null)
			ret = -1;
		else {
			ret = auth.getUser().getId();
		}
		
		return ret;
	}
	
	@WebMethod
	public String getRoleByToken(Integer token) {
		Authenticated auth = em.find( Authenticated.class, token);
		
		if ( auth == null )
			throw  new AccessControlException("Nessun utente loggato con toke <" + token + ">");
		
		auth.setLastAccess( new Date() );
		em.merge(auth);
			
		if  ( auth.getUser()  instanceof ProfileClient )
			return "client";
		if  ( auth.getUser()  instanceof ProfileAdmin )
			return "admin";
		
		return "unknowrole";
	}
	
	private void createEspireTimer(int token) {
		timerService.createTimer(1000*60*10, ""+ token );
	}

	@Timeout
	public void checkUserLastAccess(javax.ejb.Timer timer) {
		Integer token =  Integer.parseInt( timer.getInfo().toString() );
		Authenticated auth = em.find(Authenticated.class, token);
		
		System.out.println("---------------------");
		System.out.println("Received Timer event: " + timer.getInfo());
		System.out.println("---------------------");
			
		if ( auth != null ) {
			Date now = new Date();
			long diff = now.getTime() - auth.getLastAccess().getTime();
	
			if (diff > (1000 * 60 * 30)) {

				logOut( auth.getId() );
				System.out.println(auth.getUser().getLoginId() + " tempo scaduto");
			}
			else {
				createEspireTimer(token);
				System.out.println(auth.getUser().getLoginId() + " ha ancora tempo ");
			}
		}
		else {
			System.out.println("Gia logOut");
		}
		
		timer.cancel();
	}
	
	@Override
	public void ejbTimeout(Timer arg0) {

	}
	
	@WebMethod
	public ProfileClient getClientProfile(Integer token){
		Authenticated auth = em.find( Authenticated.class, new Integer(token));
		if (auth!=null){
			ProfileClient client = em.find(ProfileClient.class, auth.getUser().getId());
			return client;
		}
		return null;
	}
}
